package com.igoal.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.tuckey.web.filters.urlrewrite.utils.StringUtils;

import com.igoal.dao.NewsDAO;
import com.igoal.dao.RandomNewsDAO;
import com.igoal.dao.UserDAOExt;
import com.igoal.dao.UserLikeDAO;
import com.igoal.dto.NewsDTO;
import com.igoal.dto.TagDTO;
import com.igoal.entity.ComponentEnum;
import com.igoal.entity.News;
import com.igoal.entity.RandomNews;
import com.igoal.entity.User;
import com.igoal.entity.factory.EntityFactory;
import com.igoal.web.Constants;

@Service("newsService")
public class NewsManagerImpl extends BaseService<NewsDTO, News, Long> implements NewsManager {
	private NewsDAO newsDAO;
	@Qualifier("userDAOExt")
	private UserDAOExt userDAO;
	private RandomNewsDAO randomNewsDAO;
	private UserLikeDAO userLikeDAO;
	
	private TagService tagService;
	private CommentService commentService;
	
	@Autowired
	public void setRandomNewsDAO(RandomNewsDAO randomNewsDAO) {
		this.randomNewsDAO = randomNewsDAO;
	}

	@Autowired
	public void setCommentService(CommentService commentService) {
		this.commentService = commentService;
	}

	@Autowired
	public void setTagService(TagService tagService) {
		this.tagService = tagService;
	}

	@Autowired
	public void setUserDAO(UserDAOExt userDAO) {
		this.userDAO = userDAO;
	}

	@Autowired
	public void setNewsDAO(NewsDAO newsDAO) {
		this.newsDAO = newsDAO;
	}
	
	@Autowired
	public void setUserLikeDAO(UserLikeDAO userLikeDAO) {
		this.userLikeDAO = userLikeDAO;
	}

	public NewsManagerImpl() {
		logger = LogFactory.getLog(NewsManagerImpl.class);
	}

	public List<News> getAll() {
		return newsDAO.getAll();
	}

	public News get(Long id) {
		return newsDAO.get(id);
	}

	public boolean exists(Long id) {
		return newsDAO.exists(id);
	}

	public News save(News object) {
		return newsDAO.save(object);
	}

	public void remove(Long id) {
		newsDAO.remove(id);
	}
	
	public NewsDTO loadNews(Long id){
		News news = get(id);
		
		if(news != null){
			String username = getUserInSession();
			User user = null;
			if(isLoginUser()){
				user = (User) userDAO.loadUserByUsername(username);
			}
			
			NewsDTO dto = new NewsDTO();
			dto.initFrom(news);
			tagService.initTags(dto, dto.getId(), ComponentEnum.NEWS);
			if(dto.getTags() != null){
				StringBuffer tagNames = new StringBuffer();
				for(TagDTO tag : dto.getTags()){
					if(tagNames.length() > 0){
						tagNames.append(",");
					}
					tagNames.append(tag.getTagName());
				}
				dto.setTagNames(tagNames.toString());
			}
			commentService.loadComments(dto, ComponentEnum.NEWS);
			
			if(user != null){
				loadYouLikeThis(user.getId(), dto);
			}
			
			int likeCount = userLikeDAO.countComponentLike(ComponentEnum.NEWS, news.getId());
			dto.setLikeCount(likeCount);
			
			return dto;
		}
		
		return null;
	}

	public List<NewsDTO> listNews(Date lastNewsCreateDate, boolean before) {
		List<News> newses = newsDAO.getNewsUsingPaging(lastNewsCreateDate, before, Constants.MAX_NEWS_PER_PAGE);
		
		String username = getUserInSession();
		User user = null;
		if(isLoginUser()){
			user = (User) userDAO.loadUserByUsername(username);
		}
		
		List<NewsDTO> result = new ArrayList<NewsDTO>();
		for(News news : newses){
			NewsDTO dto = new NewsDTO();
			dto.initFrom(news);			
			tagService.initTags(dto, dto.getId(), ComponentEnum.NEWS);
			commentService.loadComments(dto, ComponentEnum.NEWS);
			if(user != null){
				loadYouLikeThis(user.getId(), dto);
			}
			int likeCount = userLikeDAO.countComponentLike(ComponentEnum.NEWS, news.getId());
			dto.setLikeCount(likeCount);
			result.add(dto);
		}
		
		return result;
	}

	public NewsDTO addNews(String username, NewsDTO dto) {
		if(!StringUtils.isBlank(username) && dto != null){
			try{
				User user = (User) userDAO.loadUserByUsername(username);
				News news = EntityFactory.createNews(user);
				dto.copyAttributesTo(news);
				updateEntity(news);
				news = newsDAO.save(news);
				addTags(username, news.getId(), dto.getListTagNames());
				dto.initFrom(news);
				return dto;
			}catch (Exception e) {
				logger.error(e);
			}			
		}
		return null;
	}
	
	public NewsDTO updateNews(String username, NewsDTO dto){
		if(!StringUtils.isBlank(username) && dto != null){
			try{
				UserDetails user = userDAO.loadUserByUsername(username);
				if(isAdmin(user)){
					News news = newsDAO.get(dto.getId());
					dto.copyAttributesTo(news);
					updateEntity(news);
					news = newsDAO.save(news);
					addTags(username, news.getId(), dto.getListTagNames());
					dto.initFrom(news);
					return dto;
				}else{
					logger.warn("NON-ADMIN-USER ["+user.getUsername()+"] tried update news["+dto.getTitle()+"]");
				}
			}catch (Exception e) {
				logger.error(e);
			}
		}
		return null;
	}
	
	void addTags(String username, Long newsId, String[] tagNames){	
		if(tagNames == null || tagNames.length == 0)
			return;
		tagService.removeAllTag(ComponentEnum.NEWS, newsId);
		tagService.tagComponent(username, null, tagNames, ComponentEnum.NEWS, newsId);
	}
	
	public NewsDTO getRandomNews(){
		RandomNews randomNews = randomNewsDAO.getRandomNews();
		if(randomNews != null){
			News news = randomNews.getNews();
			NewsDTO dto = new NewsDTO();
			dto.initFrom(news);
			return dto;
		} 
		
		return null;
	}	
	
	public void loadYouLikeThis(Long userId, NewsDTO news){
		boolean likeThis = userLikeDAO.isLikedThis(userId, ComponentEnum.NEWS, news.getId());
		news.setYouLikeThis(likeThis);
	}
}
